/**
 * Created with CLion.
 * Description: 
 * User: loong
 * Date: 2024/9/3
 * Time: 20:48
 */
#include "GroupService.h"
#include <DataHandle.h>
#include <Group.grpc.pb.h>
#include <gmock/gmock.h>
#include <grpc++/grpc++.h>
#include <gtest/gtest.h>
class MockDataHandle final : public DataHandle
{
public:
    MOCK_METHOD(bool, AddUser, (const UserInfoSPtr & _info), (override));
    MOCK_METHOD(bool, RemoveUser, (const std::string & _id), (override));
    MOCK_METHOD(UserInfoSPtr, FindUser, (const std::string & _id), (override));
    MOCK_METHOD(bool, AddGroup, (const GroupInfoSPtr & _info), (override));
    MOCK_METHOD(bool, RemoveGroup, (const std::string & _id), (override));
    MOCK_METHOD(GroupInfoVec, FindGroupWithNameLike, (const std::string & _name), (override));
    MOCK_METHOD(GroupInfoVec, FindGroupWithIDLike, (const std::string & _id), (override));
    MOCK_METHOD(bool, JoinGroup, (const std::string & _group_id, const std::string & _user_id), (override));
    MOCK_METHOD(bool, ExitGroup, (const std::string & _group_id, const std::string & _user_id), (override));
    MOCK_METHOD(bool, ModifyGroupMemberRole, (const std::string & _group_id, const std::string & _user_id, GroupInfo::Type _type), (override));
    MOCK_METHOD(GroupInfo::Type, UserType, (const std::string & _group_id, const std::string & _user_id), (override));
    MOCK_METHOD(bool, MemberIsExist, (const std::string & _group_id, const std::string & _user_id), (override));
    MOCK_METHOD(UserInfoVec, Members, (const std::string & _group_id), (override));
};

class GroupServiceTest : public ::testing::Test
{
protected:
    void SetUp() override
    {
        // 初始化 gRPC 服务
        std::string         server_address("127.0.0.1:50051");
        grpc::ServerBuilder builder;
        builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
        builder.RegisterService(&service_);
        server_ = builder.BuildAndStart();

        client_stub_ = Chat::GroupService::NewStub(grpc::CreateChannel(server_address, grpc::InsecureChannelCredentials()));

        service_.SetDataHandle(mock_handle_);
    }

    void TearDown() override
    {
        server_->Shutdown();
        server_->Wait();
    }

    std::unique_ptr<grpc::Server>             server_;
    std::unique_ptr<Chat::GroupService::Stub> client_stub_;
    GroupService                              service_;
    std::shared_ptr<MockDataHandle>           mock_handle_ = std::make_shared<MockDataHandle>();
};

MATCHER_P(UserInfoEqual, expected, "")
{
    return (arg->name == expected->name) && (arg->id == expected->id);
}

MATCHER_P(GroupInfoEqual, expected, "")
{
    return (arg->name == expected->name) && (arg->id == expected->id);
}

TEST_F(GroupServiceTest, SearchGroupTest)
{
    GroupInfoVec mockResult = {
            std::make_shared<GroupInfo>(GroupInfo {"group1_name", "group1_id"}),
            std::make_shared<GroupInfo>(GroupInfo {"group2_name", "group2_id"})};

    EXPECT_CALL(*mock_handle_, FindGroupWithNameLike("group"))
            .WillOnce(::testing::Return(mockResult))
            .WillOnce(::testing::Return(GroupInfoVec()));

    {
        Chat::SearchGroupRequest request;
        Chat::SearchGroupReply   reply;
        grpc::ClientContext      context;

        request.set_group_name("group");
        grpc::Status status = client_stub_->SearchGroup(&context, request, &reply);

        EXPECT_TRUE(status.ok());

        auto info = reply.group_info();
        EXPECT_EQ(info.size(), 2);
        EXPECT_EQ(info.at("group1_id"), "group1_name");
        EXPECT_EQ(info.at("group2_id"), "group2_name");
    }

    {
        Chat::SearchGroupRequest request;
        Chat::SearchGroupReply   reply;
        grpc::ClientContext      context;

        request.set_group_name("group");
        grpc::Status status = client_stub_->SearchGroup(&context, request, &reply);

        EXPECT_TRUE(status.ok());

        auto info = reply.group_info();
        EXPECT_TRUE(info.empty());
    }
}

TEST_F(GroupServiceTest, CreateGroupTest)
{
    auto group = std::make_shared<GroupInfo>(GroupInfo {"group1_name", "10000"});
    EXPECT_CALL(*mock_handle_, AddGroup(GroupInfoEqual(group)))
            .WillOnce(::testing::Return(false))
            .WillRepeatedly(::testing::Return(true));

    {
        Chat::CreateGroupRequest request;
        Chat::CreateGroupReply   reply;
        grpc::ClientContext      context;

        request.set_group_name("group1_name");
        request.set_group_id("10000");
        request.set_creator_id("user1_id");

        grpc::Status status = client_stub_->CreateGroup(&context, request, &reply);

        EXPECT_EQ(status.error_code(), grpc::StatusCode::ABORTED);
        EXPECT_EQ(status.error_message(), "Group create fail!");
    }

    EXPECT_CALL(*mock_handle_, JoinGroup("10000", "user1_id"))
            .WillOnce(::testing::Return(false))
            .WillRepeatedly(::testing::Return(true));

    {
        Chat::CreateGroupRequest request;
        Chat::CreateGroupReply   reply;
        grpc::ClientContext      context;

        request.set_group_name("group1_name");
        request.set_group_id("10000");
        request.set_creator_id("user1_id");

        grpc::Status status = client_stub_->CreateGroup(&context, request, &reply);

        EXPECT_EQ(status.error_code(), grpc::StatusCode::ABORTED);
        EXPECT_EQ(status.error_message(), "Group join fail!");
    }

    EXPECT_CALL(*mock_handle_, ModifyGroupMemberRole("10000", "user1_id", GroupInfo::Creator))
            .WillOnce(::testing::Return(false))
            .WillRepeatedly(::testing::Return(true));

    {
        Chat::CreateGroupRequest request;
        Chat::CreateGroupReply   reply;
        grpc::ClientContext      context;

        request.set_group_name("group1_name");
        request.set_group_id("10000");
        request.set_creator_id("user1_id");

        grpc::Status status = client_stub_->CreateGroup(&context, request, &reply);

        EXPECT_EQ(status.error_code(), grpc::StatusCode::ABORTED);
        EXPECT_EQ(status.error_message(), "Modify role fail!");
    }

    {
        Chat::CreateGroupRequest request;
        Chat::CreateGroupReply   reply;
        grpc::ClientContext      context;

        request.set_group_name("group1_name");
        request.set_group_id("10000");
        request.set_creator_id("user1_id");

        grpc::Status status = client_stub_->CreateGroup(&context, request, &reply);

        EXPECT_TRUE(status.ok());
        EXPECT_EQ(reply.group_id(), "10000");
    }
}

TEST_F(GroupServiceTest, JoinGroupTest)
{
    EXPECT_CALL(*mock_handle_, JoinGroup("测试组ID", "测试用户ID"))
            .WillOnce(::testing::Return(false))
            .WillRepeatedly(::testing::Return(true));

    {
        Chat::JoinGroupRequest request;
        Chat::CommonGroupReply    reply;
        grpc::ClientContext       context;

        request.set_group_id("测试组ID");
        request.set_user_id("测试用户ID");

        auto status = client_stub_->JoinGroup(&context, request, &reply);

        EXPECT_EQ(status.error_code(), grpc::StatusCode::ABORTED);
        EXPECT_EQ(status.error_message(), "Group join fail!");
    }

    {
        Chat::JoinGroupRequest request;
        Chat::CommonGroupReply    reply;
        grpc::ClientContext       context;

        request.set_group_id("测试组ID");
        request.set_user_id("测试用户ID");

        auto status = client_stub_->JoinGroup(&context, request, &reply);

        EXPECT_TRUE(status.ok());
        EXPECT_EQ(reply.message(), "欢迎加入: 测试组ID");
    }
}

TEST_F(GroupServiceTest, InviteJoinGroupTest)
{
    EXPECT_CALL(*mock_handle_, MemberIsExist("测试组ID", "测试用户"))
            .WillOnce(::testing::Return(true))
            .WillRepeatedly(::testing::Return(false));

    {
        Chat::InviteJoinGroupRequest request;
        Chat::CommonGroupReply    reply;
        grpc::ClientContext       context;

        request.set_group_id("测试组ID");
        request.set_user_id("测试用户ID");
        request.set_invite_id("测试用户");

        auto status = client_stub_->InviteJoinGroup(&context, request, &reply);

        EXPECT_EQ(status.error_code(), grpc::StatusCode::CANCELLED);
        EXPECT_EQ(status.error_message(), "User is already in group!");
    }

    EXPECT_CALL(*mock_handle_, JoinGroup("测试组ID", "测试用户ID"))
                .WillOnce(::testing::Return(false))
                .WillRepeatedly(::testing::Return(true));

    {
        Chat::InviteJoinGroupRequest request;
        Chat::CommonGroupReply    reply;
        grpc::ClientContext       context;

        request.set_group_id("测试组ID");
        request.set_user_id("测试用户ID");
        request.set_invite_id("测试用户");

        auto status = client_stub_->InviteJoinGroup(&context, request, &reply);

        EXPECT_EQ(status.error_code(), grpc::StatusCode::ABORTED);
        EXPECT_EQ(status.error_message(), "Invite join group fail!");
    }

    {
        Chat::InviteJoinGroupRequest request;
        Chat::CommonGroupReply    reply;
        grpc::ClientContext       context;

        request.set_group_id("测试组ID");
        request.set_user_id("测试用户ID");
        request.set_invite_id("测试用户");

        auto status = client_stub_->InviteJoinGroup(&context, request, &reply);

        EXPECT_TRUE(status.ok());
        EXPECT_EQ(reply.message(), "欢迎加入: 测试组ID");
    }
}

TEST_F(GroupServiceTest, ExitGroupTest)
{
    EXPECT_CALL(*mock_handle_, MemberIsExist("测试组ID", "测试用户"))
            .WillOnce(::testing::Return(false))
            .WillRepeatedly(::testing::Return(true));

    {
        Chat::ExitGroupRequest request;
        Chat::CommonGroupReply    reply;
        grpc::ClientContext       context;

        request.set_group_id("测试组ID");
        request.set_user_id("测试用户");

        auto status = client_stub_->ExitGroup(&context, request, &reply);

        EXPECT_EQ(status.error_code(), grpc::StatusCode::NOT_FOUND);
        EXPECT_EQ(status.error_message(), "User is not in group");
    }

    EXPECT_CALL(*mock_handle_, ExitGroup("测试组ID", "测试用户"))
            .WillOnce(::testing::Return(false))
            .WillRepeatedly(::testing::Return(true));

    {
        Chat::ExitGroupRequest request;
        Chat::CommonGroupReply    reply;
        grpc::ClientContext       context;

        request.set_group_id("测试组ID");
        request.set_user_id("测试用户");

        auto status = client_stub_->ExitGroup(&context, request, &reply);

        EXPECT_EQ(status.error_code(), grpc::StatusCode::ABORTED);
        EXPECT_EQ(status.error_message(), "Group exit fail!");
    }

    {
        Chat::ExitGroupRequest request;
        Chat::CommonGroupReply    reply;
        grpc::ClientContext       context;

        request.set_group_id("测试组ID");
        request.set_user_id("测试用户");

        auto status = client_stub_->ExitGroup(&context, request, &reply);

        EXPECT_TRUE(status.ok());
        EXPECT_EQ(reply.message(), "Group exit successful!");
    }
}

TEST_F(GroupServiceTest, KickOutTest)
{
    EXPECT_CALL(*mock_handle_, MemberIsExist("测试组ID", "测试用户"))
            .WillOnce(::testing::Return(false))
            .WillRepeatedly(::testing::Return(true));

    {
        Chat::KickOutRequest request;
        Chat::CommonGroupReply    reply;
        grpc::ClientContext       context;

        request.set_group_id("测试组ID");
        request.set_user_id("测试用户");

        auto status = client_stub_->KickOut(&context, request, &reply);

        EXPECT_EQ(status.error_code(), grpc::StatusCode::NOT_FOUND);
        EXPECT_EQ(status.error_message(), "User is not in group");
    }

    EXPECT_CALL(*mock_handle_, ExitGroup("测试组ID", "测试用户"))
            .WillOnce(::testing::Return(false))
            .WillRepeatedly(::testing::Return(true));

    {
        Chat::KickOutRequest request;
        Chat::CommonGroupReply    reply;
        grpc::ClientContext       context;

        request.set_group_id("测试组ID");
        request.set_user_id("测试用户");

        auto status = client_stub_->KickOut(&context, request, &reply);

        EXPECT_EQ(status.error_code(), grpc::StatusCode::ABORTED);
        EXPECT_EQ(status.error_message(), "KickOut fail!");
    }

    {
        Chat::KickOutRequest request;
        Chat::CommonGroupReply    reply;
        grpc::ClientContext       context;

        request.set_group_id("测试组ID");
        request.set_user_id("测试用户");

        auto status = client_stub_->KickOut(&context, request, &reply);

        EXPECT_TRUE(status.ok());
        EXPECT_EQ(reply.message(), "测试用户 KickOut successful!");
    }
}

TEST_F(GroupServiceTest, DisbandGroupTest)
{
    EXPECT_CALL(*mock_handle_, MemberIsExist("测试组ID", "测试用户"))
            .WillOnce(::testing::Return(false))
            .WillRepeatedly(::testing::Return(true));

    {
        Chat::DisbandGroupRequest request;
        Chat::CommonGroupReply    reply;
        grpc::ClientContext       context;

        request.set_group_id("测试组ID");
        request.set_user_id("测试用户");

        auto status = client_stub_->DisbandGroup(&context, request, &reply);

        EXPECT_EQ(status.error_code(), grpc::StatusCode::NOT_FOUND);
        EXPECT_EQ(status.error_message(), "User is not in group");
    }

    EXPECT_CALL(*mock_handle_, UserType("测试组ID", "测试用户"))
            .WillOnce(::testing::Return(GroupInfo::Normal))
            .WillRepeatedly(::testing::Return(GroupInfo::Creator));

    {
        Chat::DisbandGroupRequest request;
        Chat::CommonGroupReply    reply;
        grpc::ClientContext       context;

        request.set_group_id("测试组ID");
        request.set_user_id("测试用户");

        auto status = client_stub_->DisbandGroup(&context, request, &reply);

        EXPECT_EQ(status.error_code(), grpc::StatusCode::ABORTED);
        EXPECT_EQ(status.error_message(), "User is not creator");
    }

    UserInfoVec mockResult = {
            std::make_shared<UserInfo>(UserInfo {"user1_name", "user1_id"}),
        std::make_shared<UserInfo>(UserInfo {"user2_name", "user2_id"})};

    EXPECT_CALL(*mock_handle_, Members("测试组ID"))
            .WillRepeatedly(::testing::Return(mockResult));

    EXPECT_CALL(*mock_handle_, ExitGroup(::testing::_, ::testing::_))
                .WillRepeatedly(::testing::Return(true));

    EXPECT_CALL(*mock_handle_, RemoveGroup("测试组ID"))
        .WillOnce(::testing::Return(false))
        .WillRepeatedly(::testing::Return(true));

    {
        Chat::DisbandGroupRequest request;
        Chat::CommonGroupReply    reply;
        grpc::ClientContext       context;

        request.set_group_id("测试组ID");
        request.set_user_id("测试用户");

        auto status = client_stub_->DisbandGroup(&context, request, &reply);

        EXPECT_EQ(status.error_code(), grpc::StatusCode::ABORTED);
        EXPECT_EQ(status.error_message(), "Group disband fail!");
    }

    {
        Chat::DisbandGroupRequest request;
        Chat::CommonGroupReply    reply;
        grpc::ClientContext       context;

        request.set_group_id("测试组ID");
        request.set_user_id("测试用户");

        auto status = client_stub_->DisbandGroup(&context, request, &reply);

        EXPECT_TRUE(status.ok());
        EXPECT_EQ(reply.message(), "Group disband successful!");
    }
}